package com.iteaj.izone.web.shiro;

import com.iteaj.izone.api.LoggerType;
import com.iteaj.izone.spi.AuthorizingService;
import com.iteaj.izone.spi.AuthzUrl;
import com.iteaj.izone.spi.event.EventPublisher;
import com.iteaj.util.Result;
import com.iteaj.util.module.mvc.HttpResult;
import com.iteaj.util.module.mvc.orm.Entity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.subject.WebSubject;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * create time: 2020/4/22
 *
 * @author iteaj
 * @since 1.0
 */
public abstract class AbstractShiroAuthorService implements AuthorizingService<ShiroAuthToken> {

    private AuthzUrl authzUrl;
    private EventPublisher eventPublisher;

    @Override
    public Result login(ShiroAuthToken token) {
        long start = System.currentTimeMillis();
        WebSubject subject = (WebSubject) SecurityUtils.getSubject();
        String msg = "";
        try {
            // 登录
            subject.login(token);
        } catch (UnknownAccountException e) {
            msg = "账号不存在";
            logger.error("账号不存在", e);
            return HttpResult.Fail("账号不存在");
        } catch (CredentialsException e) {
            msg = "账号密码不匹配";
            logger.error("账号密码不匹配", e);
            return HttpResult.Fail("账号密码不匹配");
        } catch (AuthenticationException e) {
            msg = "认证失败";
            logger.error("认证失败", e);
            return HttpResult.Fail(e.getMessage());
        } catch (Exception e) {
            msg = "认证失败";
            logger.error(e.getMessage(), e);
            return HttpResult.Fail("认证失败");
        } finally {
            long time = System.currentTimeMillis() - start;

            Object source = subject.getPrincipal();
            if(source == null) source = token;

            ShiroAuthorEvent event = new ShiroAuthorEvent(source
                    , (ShiroHttpServletRequest)subject.getServletRequest()
                    , LoggerType.Login).setMethod(null).setErrMsg(msg)
                    .setOperaTimeMillis(time).setArgs(new Object[]{token});
            this.eventPublisher.publish(event);
        }

        return HttpResult.Success("认证成功").add("successUrl"
                , getAuthzUrl().getSuccessUrl());
    }

    @Override
    public Result logout(Entity admin) {
        String msg = "注销成功";
        WebSubject subject = (WebSubject) SecurityUtils.getSubject();
        long start = System.currentTimeMillis();
        try {
            subject.logout();
        } catch (Exception e) {
            msg = "注销失败";
            logger.error(e.getMessage(), e);
            return HttpResult.Fail("注销失败");
        } finally {
            long time = System.currentTimeMillis() - start;

            ShiroAuthorEvent event = new ShiroAuthorEvent(admin
                    , (ShiroHttpServletRequest)subject.getServletRequest()
                    , LoggerType.Logout).setMethod(null).setErrMsg(msg)
                    .setOperaTimeMillis(time).setArgs(new Object[]{admin});
            this.getEventPublisher().publish(event);
        }
        return HttpResult.Success("注销成功").add("loginUrl"
                , getAuthzUrl().getLoginUrl());
    }

    public EventPublisher getEventPublisher() {
        return eventPublisher;
    }

    @Autowired
    public AbstractShiroAuthorService setEventPublisher(EventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
        return this;
    }

    @Override
    public AuthzUrl getAuthzUrl() {
        return authzUrl;
    }

    @Autowired
    public AbstractShiroAuthorService setAuthzUrl(AuthzUrl authzUrl) {
        this.authzUrl = authzUrl;
        return this;
    }
}
